
function cursor($hover) {
	if (window.matchMedia("(hover: hover)").matches) {
		new Cursor($hover);
	}
}

const math = {
	lerp: (a, b, n) => { return (1 - n) * a + n * b }
}

const html = `
	body, a {
		cursor: none;
	}
	#cursor {
		pointer-events: none;
	}
	#cursor svg {
		position: fixed;
		top: 0;
		left: 0;
		fill: #fff;
		opacity: .9;
		mix-blend-mode: difference;
		z-index: 999;
		transition: .2s ease-in-out;
		transition-property: fill, opacity, transform;
	}
	#cursor.hidden svg {
		opacity: 0;
	}
	#cursor.hover svg:last-child {
		fill: #222;
		transform: scale(3);
	}
	#cursor.active svg:last-child {
		opacity: 0;
		transform: scale(.33);
	}
`;

class Cursor {
	constructor($hover) {
		this.pos = {curr: null, prev: null};
		this.hov = [...document.querySelectorAll($hover)];
		this.init();
		this.move();
	}

	init() {
		if (!this.cursor) {
			this.cursor = document.createElement("div");
			this.cursor.id = "cursor";
			this.cursor.className = "hidden";
			this.cursor.innerHTML = `
				<svg width="8" height="8"><circle cx="4" cy="4" r="4"></circle></svg>
				<svg width="24" height="24"><circle cx="12" cy="12" r="12"></circle></svg>
			`;
			document.body.append(this.cursor);
			if (document.querySelector("style")) {
				document.querySelector("style").append(html);
			} else {
				document.body.appendChild(document.createElement("style")).append(html);
			}
		}

		document.body.addEventListener("mousemove", (e) => {
			this.cursor.firstElementChild.style.left = `${e.clientX - 4}px`;
			this.cursor.firstElementChild.style.top  = `${e.clientY - 4}px`;
			this.pos.curr = {
				x: e.clientX,
				y: e.clientY
			};
		});
		document.body.addEventListener("mouseover", (e) => {
			this.hov.includes(e.target) && this.cursor.classList.add("hover");
			e.target.dataset.hover && (this.cursor.lastElementChild.style.fill = e.target.dataset.hover);
		});
		document.body.addEventListener("mouseout", (e) => {
			this.hov.includes(e.target) && this.cursor.classList.remove("hover");
			e.target.dataset.hover && (this.cursor.lastElementChild.style.fill = null);
		});
		document.body.addEventListener("mouseenter", (e) => {
			if (!this.pos.prev) {
				this.cursor.firstElementChild.style.left = `${e.clientX - 4}px`;
				this.cursor.firstElementChild.style.top  = `${e.clientY - 4}px`;
				this.cursor.lastElementChild.style.left = `${e.clientX - 12}px`;
				this.cursor.lastElementChild.style.top  = `${e.clientY - 12}px`;
			}
			this.cursor.classList.remove("hidden");
		});
		document.body.addEventListener("mouseleave", (e) => {
			this.cursor.classList.add("hidden");
		});
		document.body.addEventListener("mouseup", () => {
			this.cursor.classList.remove("active");
		});
		document.body.addEventListener("mousedown", () => {
			this.cursor.classList.add("active");
		});
	}

	move() {
		if (this.pos.prev) {
			this.pos.prev.x = math.lerp(this.pos.prev.x, this.pos.curr.x, 0.15);
			this.pos.prev.y = math.lerp(this.pos.prev.y, this.pos.curr.y, 0.15);
			this.cursor.lastElementChild.style.left = `${this.pos.prev.x - 12}px`;
			this.cursor.lastElementChild.style.top  = `${this.pos.prev.y - 12}px`;
		} else {
			this.pos.prev = this.pos.curr;
		}
		requestAnimationFrame(() => this.move());
	}
}